﻿#include "dlgmodbusrtu.h"
#include "ui_dlgmodbusrtu.h"
#include "util/byteutil.h"

#include <QDebug>
#include <QCloseEvent>
#include <QTimer>
#include <QInputDialog>
#include <QMessageBox>

DlgModbusRtu::DlgModbusRtu(QSettings* settings, SerialPort* serialPort, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::DlgModbusRtu),
    m_settings(settings),
    m_serialPort(serialPort)
{
    ui->setupUi(this);

    // 初始化
    initUI();
    init();
}

DlgModbusRtu::~DlgModbusRtu()
{
    delete ui;
}

void DlgModbusRtu::closeEvent(QCloseEvent *event)
{
    // 对话框关闭时关闭串口
    m_serialPort->close();

    event->accept();
}

void DlgModbusRtu::initUI()
{
    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
    setFixedSize(this->width(), this->height());

    m_serialPortOpened.load(":res/image/green.png");
    m_serialPortClosed.load(":res/image/gray.png");
    ui->lblSerialPortStatus->setPixmap(m_serialPortClosed);
    ui->lblSerialPortStatus->setScaledContents(true);

    // 单选按钮分组
    m_bgReadWrite = new QButtonGroup(this);
    m_bgReadWrite->addButton(ui->rdoRead, 0);
    m_bgReadWrite->addButton(ui->rdoWrite, 1);
    connect(m_bgReadWrite, QOverload<int>::of(&QButtonGroup::buttonClicked), this, &DlgModbusRtu::onReadWriteChanged);

    connect(ui->btnOpenSerialPort, &QPushButton::clicked, this, &DlgModbusRtu::onOpenSerialPort);
    connect(ui->btnSaveRegister, &QPushButton::clicked, this, &DlgModbusRtu::onSaveRegister);
    connect(ui->btnHardwareVersion, &QPushButton::clicked, this, &DlgModbusRtu::onHardwareVersion);
    connect(ui->btnSoftwareVersion, &QPushButton::clicked, this, &DlgModbusRtu::onSoftwareVersion);
    connect(ui->btnStatusRegister, &QPushButton::clicked, this, &DlgModbusRtu::onStatusRegister);
    connect(ui->btnRealtimePosition, &QPushButton::clicked, this, &DlgModbusRtu::onRealtimePosition);
    connect(ui->btnRealtimeSpeed, &QPushButton::clicked, this, &DlgModbusRtu::onRealtimeSpeed);
    connect(ui->btnRealtimeCurrent, &QPushButton::clicked, this, &DlgModbusRtu::onRealtimeCurrent);
    connect(ui->btnSubdivision32, &QPushButton::clicked, this, &DlgModbusRtu::onSubdivision32);
    connect(ui->btnMotorDirection, &QPushButton::clicked, this, &DlgModbusRtu::onMotorDirection);
    connect(ui->btnMotorEnable, &QPushButton::clicked, this, &DlgModbusRtu::onMotorEnable);
    connect(ui->btnZero, &QPushButton::clicked, this, &DlgModbusRtu::onZero);
    connect(ui->btnTwoZero, &QPushButton::clicked, this, &DlgModbusRtu::onTwoZero);
    connect(ui->btnZeroRun, &QPushButton::clicked, this, &DlgModbusRtu::onZeroRun);
    connect(ui->btnRunSpeed, &QPushButton::clicked, this, &DlgModbusRtu::onRunSpeed);
    connect(ui->btnRunStop, &QPushButton::clicked, this, &DlgModbusRtu::onRunStop);
    connect(ui->btnPointMove, &QPushButton::clicked, this, &DlgModbusRtu::onPointMove);
    connect(ui->btnRunTime, &QPushButton::clicked, this, &DlgModbusRtu::onRunTime);
    connect(ui->btnRunImpulse, &QPushButton::clicked, this, &DlgModbusRtu::onRunImpulse);
    connect(ui->btnRunAbsolutePosition, &QPushButton::clicked, this, &DlgModbusRtu::onRunAbsolutePosition);
    connect(ui->btnSetAbsolutePosition, &QPushButton::clicked, this, &DlgModbusRtu::onSetAbsolutePosition);
    connect(ui->btnReadWarning, &QPushButton::clicked, this, &DlgModbusRtu::onReadWarning);
    connect(ui->btnClearWarning, &QPushButton::clicked, this, &DlgModbusRtu::onClearWarning);

    connect(ui->btnSend, &QPushButton::clicked, this, &DlgModbusRtu::onSend);
}

void DlgModbusRtu::init()
{
    // 串口打开标识
    m_opened = false;

    // 串口读取等待时间
    m_settings->beginGroup("SerialPort");
    m_readWaitInterval = m_settings->value("readWaitInterval").toInt();
    m_settings->endGroup();
}

void DlgModbusRtu::readSingleRegister(unsigned short address, unsigned short num)
{
    QByteArray cmd(8, 0x0);
    cmd[0] = 0x01;  // 站号
    cmd[1] = 0x03;  // 功能码
    cmd[2] = static_cast<char>((address >> 8) & 0xFF);  // 起始地址高位
    cmd[3] = static_cast<char>(address & 0xFF);         // 起始地址低位
    cmd[4] = static_cast<char>((num >> 8) & 0xFF);      // 总寄存器高位
    cmd[5] = static_cast<char>(num & 0xFF);             // 总寄存器低位
    // 校验
    char* data = cmd.data();
    unsigned short crc = do_crc_table(reinterpret_cast<unsigned char*>(data), 6);
    cmd[6] = static_cast<char>(crc & 0xFF);
    cmd[7] = static_cast<char>((crc >> 8) & 0xFF);

    m_serialPort->clear();
    m_serialPort->write(cmd);
    ui->leSend->setText(cmd.toHex(' '));
}

void DlgModbusRtu::writeSingleRegister(unsigned short address, unsigned short value)
{
    QByteArray cmd(8, 0x0);
    cmd[0] = 0x01;  // 站号
    cmd[1] = 0x06;  // 功能码
    cmd[2] = static_cast<char>((address >> 8) & 0xFF);    // 起始地址高位
    cmd[3] = static_cast<char>(address & 0xFF);           // 起始地址低位
    cmd[4] = static_cast<char>((value >> 8) & 0xFF);      // 寄存器值高位
    cmd[5] = static_cast<char>(value & 0xFF);             // 寄存器值低位
    // 校验
    char* data = cmd.data();
    unsigned short crc = do_crc_table(reinterpret_cast<unsigned char*>(data), 6);
    cmd[6] = static_cast<char>(crc & 0xFF);
    cmd[7] = static_cast<char>((crc >> 8) & 0xFF);

    m_serialPort->clear();
    m_serialPort->write(cmd);
    ui->leSend->setText(cmd.toHex(' '));

    QTimer::singleShot(m_readWaitInterval, this, [=](){ ui->leRecv->setText(m_serialPort->recvBuffer().toHex(' ')); });
}

void DlgModbusRtu::writeMultiRegister(unsigned short address, unsigned short num, const QByteArray& valueArray)
{
    QByteArray cmd(num * 2 + 9, 0x0);
    cmd[0] = 0x01;  // 站号
    cmd[1] = 0x10;  // 功能码
    cmd[2] = static_cast<char>((address >> 8) & 0xFF);    // 起始地址高位
    cmd[3] = static_cast<char>(address & 0xFF);           // 起始地址低位
    cmd[4] = static_cast<char>((num >> 8) & 0xFF );      // 寄存器总数高位
    cmd[5] = static_cast<char>(num & 0xFF);              // 寄存器总数低位
    cmd[6] = static_cast<char>(num * 2);                 // 总字节数
    // 寄存器值
    for (int i = 0; i < valueArray.size(); i++)
        cmd[i + 7] = valueArray.at(i);
    // 校验
    char* data = cmd.data();
    unsigned short crc = do_crc_table(reinterpret_cast<unsigned char*>(data), num * 2 + 7);
    cmd[num * 2 + 7] = static_cast<char>(crc & 0xFF);
    cmd[num * 2 + 8] = static_cast<char>((crc >> 8) & 0xFF);

    m_serialPort->clear();
    m_serialPort->write(cmd);
    ui->leSend->setText(cmd.toHex(' '));

    QTimer::singleShot(m_readWaitInterval, this, [=](){ ui->leRecv->setText(m_serialPort->recvBuffer().toHex(' ')); });
}

void DlgModbusRtu::onReadWriteChanged(int id)
{
    // 只读
    ui->btnHardwareVersion->setEnabled(id == 0);
    ui->btnSoftwareVersion->setEnabled(id == 0);
    ui->btnStatusRegister->setEnabled(id == 0);
    ui->btnRealtimePosition->setEnabled(id == 0);
    ui->btnRealtimeSpeed->setEnabled(id == 0);
    ui->btnRealtimeCurrent->setEnabled(id == 0);
    ui->btnReadWarning->setEnabled(id == 0);

    // 只写
    ui->btnSaveRegister->setEnabled(id == 1);
    ui->btnMotorEnable->setEnabled(id == 1);
    ui->btnZeroRun->setEnabled(id == 1);
    ui->btnRunStop->setEnabled(id == 1);
    ui->btnPointMove->setEnabled(id == 1);
    ui->btnRunTime->setEnabled(id == 1);
    ui->btnRunImpulse->setEnabled(id == 1);
    ui->btnRunAbsolutePosition->setEnabled(id == 1);
    ui->btnSetAbsolutePosition->setEnabled(id == 1);
    ui->btnClearWarning->setEnabled(id == 1);
}

void DlgModbusRtu::onOpenSerialPort()
{
    if (m_opened) {
        ui->lblSerialPortStatus->setPixmap(m_serialPortClosed);
        ui->btnOpenSerialPort->setText(QStringLiteral("打开串口"));

        m_serialPort->close();

        m_opened = false;
    } else {
        if (m_serialPort->open()) {
            ui->lblSerialPortStatus->setPixmap(m_serialPortOpened);
            ui->btnOpenSerialPort->setText(QStringLiteral("关闭串口"));
            m_opened = true;
        } else {
            QMessageBox::critical(this, QStringLiteral("错误"), QStringLiteral("串口打开失败!"));
        }
    }
}

void DlgModbusRtu::onSaveRegister()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    QMessageBox::StandardButton button = QMessageBox::question(this, QStringLiteral("RS485"), QStringLiteral("断电保存"), QMessageBox::Yes | QMessageBox::No);
    if (button == QMessageBox::Yes) {
        writeSingleRegister(0xdc, 01);
    }
}

void DlgModbusRtu::onHardwareVersion()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    readSingleRegister(0x00, 0x02);

    QTimer::singleShot(m_readWaitInterval, this, [=](){
        QByteArray recvBuffer = m_serialPort->recvBuffer();
        ui->leRecv->setText(recvBuffer.toHex(' '));

        if (recvBuffer.size() >= 9) {
            QString version = QString(QLatin1String(recvBuffer.mid(3, 4).constData()));
            ui->pteRslt->setPlainText(QStringLiteral("硬件版本号:%1").arg(version));
        }
    });
}

void DlgModbusRtu::onSoftwareVersion()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    readSingleRegister(0x02, 0x02);

    QTimer::singleShot(m_readWaitInterval, this, [=](){
        QByteArray recvBuffer = m_serialPort->recvBuffer();
        ui->leRecv->setText(recvBuffer.toHex(' '));

        if (recvBuffer.size() >= 9) {
            QString version = QString(QLatin1String(recvBuffer.mid(3, 4).constData()));
            ui->pteRslt->setPlainText(QStringLiteral("软件版本号:%1").arg(version));
        }
    });
}

void DlgModbusRtu::onStatusRegister()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    readSingleRegister(0x06, 0x01);

    QTimer::singleShot(m_readWaitInterval, this, [=](){
        QByteArray recvBuffer = m_serialPort->recvBuffer();
        ui->leRecv->setText(recvBuffer.toHex(' '));

        if (recvBuffer.size() >= 7) {
            QString input;
            for (int i = 0; i < 8; i++)
                input.prepend(QString::number((recvBuffer.at(4) >> i) & 0x1));
            QString status;
            switch (recvBuffer.at(3) & 0x03) {
            case 0x00:
                status = QStringLiteral("00(空闲)");
                break;
            case 0x01:
                status = QStringLiteral("01(启动)");
                break;
            case 0x02:
                status = QStringLiteral("10(停止)");
                break;
            case 0x03:
                status = QStringLiteral("11(运行)");
                break;
            default:
                break;
            }

            ui->pteRslt->setPlainText(QStringLiteral("输入状态: %1\n电机运行状态: %2").arg(input, status));
        }
    });
}

void DlgModbusRtu::onRealtimePosition()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    readSingleRegister(0x04, 0x02);

    QTimer::singleShot(m_readWaitInterval, this, [=](){
        QByteArray recvBuffer = m_serialPort->recvBuffer();
        ui->leRecv->setText(recvBuffer.toHex(' '));

        if (recvBuffer.size() >= 9) {
            int centerPosition = ((recvBuffer.at(5) & 0xFF) << 24) | ((recvBuffer.at(6) & 0xFF) << 16) | ((recvBuffer.at(3) & 0xFF) << 8) | (recvBuffer.at(4) & 0xFF);
            ui->pteRslt->setPlainText(QStringLiteral("电机当前绝对位置:%1").arg(centerPosition));
        }
    });
}

void DlgModbusRtu::onRealtimeSpeed()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    readSingleRegister(0x19, 0x01);

    QTimer::singleShot(m_readWaitInterval, this, [=](){
        QByteArray recvBuffer = m_serialPort->recvBuffer();
        ui->leRecv->setText(recvBuffer.toHex(' '));

        if (recvBuffer.size() >= 7) {
            unsigned short speed = recvBuffer.mid(3, 2).toUShort(nullptr, 16);
            ui->pteRslt->setPlainText(QStringLiteral("电机实际运行速度(转/分):%1").arg(speed));
        }
    });
}

void DlgModbusRtu::onRealtimeCurrent()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    readSingleRegister(0x1a, 0x01);

    QTimer::singleShot(m_readWaitInterval, this, [=](){
        QByteArray recvBuffer = m_serialPort->recvBuffer();
        ui->leRecv->setText(recvBuffer.toHex(' '));

        if (recvBuffer.size() >= 7) {
            unsigned short current = recvBuffer.mid(3, 2).toUShort(nullptr, 16);
            ui->pteRslt->setPlainText(QStringLiteral("电机实际运行电流(mA):%1").arg(current));
        }
    });
}

void DlgModbusRtu::onSubdivision32()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    if (m_bgReadWrite->checkedId() == 0) {
        readSingleRegister(0x24, 0x02);

        QTimer::singleShot(m_readWaitInterval, this, [=](){
            QByteArray recvBuffer = m_serialPort->recvBuffer();
            ui->leRecv->setText(recvBuffer.toHex(' '));

            if (recvBuffer.size() >= 9) {
                unsigned int subdivision = static_cast<unsigned int>( ((recvBuffer.at(5) & 0xFF) << 24) | ((recvBuffer.at(6) & 0xFF) << 16) | ((recvBuffer.at(3) & 0xFF) << 8) | (recvBuffer.at(4) & 0xFF) );
                ui->pteRslt->setPlainText(QStringLiteral("32位细分:%1").arg(subdivision));
            }
        });
    }

    if (m_bgReadWrite->checkedId() == 1) {
        bool ok = false;
        int subdivision = QInputDialog::getInt(this, QStringLiteral("RS485"), QStringLiteral("32位细分"), 10000, 200, 1000000, 1, &ok, Qt::MSWindowsFixedSizeDialogHint);
        if (ok) {
            QByteArray valueArray(4, 0x0);
            valueArray[0] = static_cast<char>((subdivision >> 8) & 0xFF);
            valueArray[1] = static_cast<char>(subdivision & 0xFF);
            valueArray[2] = static_cast<char>((subdivision >> 24) & 0xFF);
            valueArray[3] = static_cast<char>((subdivision >> 16) & 0xFF);
            writeMultiRegister(0x24, 0x02, valueArray);
        }
    }
}

void DlgModbusRtu::onMotorDirection()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    if (m_bgReadWrite->checkedId() == 0) {
        readSingleRegister(0x66, 0x01);

        QTimer::singleShot(m_readWaitInterval, this, [=](){
            QByteArray recvBuffer = m_serialPort->recvBuffer();
            ui->leRecv->setText(recvBuffer.toHex(' '));

            if (recvBuffer.size() >= 7) {
                unsigned short direction = recvBuffer.mid(3, 2).toUShort(nullptr, 16);
                ui->pteRslt->setPlainText(QStringLiteral("电机运行方向(0:CW; 1:CCW):%1").arg(direction));
            }
        });
    }

    if (m_bgReadWrite->checkedId() == 1) {
        unsigned short direction = 0x0;
        if (ui->rdoMotorCCW->isChecked())
            direction = 0x1;

        QMessageBox::StandardButton button = QMessageBox::question(this, QStringLiteral("RS485"), QStringLiteral("电机运行方向设置(0:CW; 1:CCW)"), QMessageBox::Yes | QMessageBox::No);
        if (button == QMessageBox::Yes) {
            writeSingleRegister(0x6b, direction);
        }
    }
}

void DlgModbusRtu::onMotorEnable()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    unsigned short value = 0;
    if (ui->rdoMotorDisable->isChecked())
        value = 1;
    if (ui->rdoMotorReset->isChecked())
        value = 256;

    QMessageBox::StandardButton button = QMessageBox::question(this, QStringLiteral("RS485"), QStringLiteral("使能(0),释放(1),重启(256)"), QMessageBox::Yes | QMessageBox::No);
    if (button == QMessageBox::Yes) {
        writeSingleRegister(0xd4, value);
    }
}

void DlgModbusRtu::onZero()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    if (m_bgReadWrite->checkedId() == 0) {
        readSingleRegister(0x9c, 0x01);

        QTimer::singleShot(m_readWaitInterval, this, [=](){
            QByteArray recvBuffer = m_serialPort->recvBuffer();
            ui->leRecv->setText(recvBuffer.toHex(' '));

            if (recvBuffer.size() >= 7) {
                QString port = QString::number(recvBuffer.at(4) & 0x0F);
                ui->pteRslt->setPlainText(QStringLiteral("设置原点端口:%1").arg(port));
            }
        });
    }

    if (m_bgReadWrite->checkedId() == 1) { 
        unsigned short value = static_cast<unsigned short>(0x30 + ui->sbZeroPort->value());
        writeSingleRegister(0x9c, value);
    }
}

void DlgModbusRtu::onTwoZero()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    if (m_bgReadWrite->checkedId() == 0) {
        readSingleRegister(0x9d, 0x01);

        QTimer::singleShot(m_readWaitInterval, this, [=](){
            QByteArray recvBuffer = m_serialPort->recvBuffer();
            ui->leRecv->setText(recvBuffer.toHex(' '));

            if (recvBuffer.size() >= 7) {
                unsigned short value = recvBuffer.mid(3, 2).toUShort(nullptr, 16);
                ui->pteRslt->setPlainText(QStringLiteral("二次回原点距离方向:%1").arg(value));
            }
        });
    }

    if (m_bgReadWrite->checkedId() == 1) {
        int value = ui->sbTwoZeroImpulse->value();
        if (ui->rdoTwoZeroCCW->isChecked())
            value += 0x8000;
        writeSingleRegister(0x9d, static_cast<unsigned short>(value));
    }
}

void DlgModbusRtu::onZeroRun()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    int value = ui->sbTwoZeroSpeed->value();
    if (ui->rdoZeroImmediateStop->isChecked())
        value += 0x20;
    value += ui->sbZeroSpeed->value() << 6;
    if (ui->rdoZeroCCW->isChecked())
        value += 0x8000;
    writeSingleRegister(0xc9, static_cast<unsigned short>(value));
}

void DlgModbusRtu::onRunSpeed()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    if (m_bgReadWrite->checkedId() == 0) {
        readSingleRegister(0x9a, 0x01);

        QTimer::singleShot(m_readWaitInterval, this, [=](){
            QByteArray recvBuffer = m_serialPort->recvBuffer();
            ui->leRecv->setText(recvBuffer.toHex(' '));

            if (recvBuffer.size() >= 7) {
                unsigned short speed = recvBuffer.mid(3, 2).toUShort(nullptr, 16);
                ui->pteRslt->setPlainText(QStringLiteral("电机运行目标速度:%1").arg(speed));
            }
        });
    }

    if (m_bgReadWrite->checkedId() == 1) {
        unsigned short speed = static_cast<unsigned short>(ui->sbRunSpeed->value());
        writeSingleRegister(0x9a, speed);
    }
}

void DlgModbusRtu::onRunStop()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    unsigned short value = 0x01;
    if (ui->rdoRunCCW->isChecked())
        value = 0x0101;
    if (ui->rdoReduceStop->isChecked())
        value = 0x00;
    if (ui->rdoEmergencyStop->isChecked())
        value = 0x0100;
    writeSingleRegister(0xc8, value);
}

void DlgModbusRtu::onPointMove()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    int value = ui->sbPonitMoveSpeed->value() << 6;
    if (ui->rdoPointMoveRun->isChecked())
        value += 0x01;
    if (ui->rdoPointMoveCCW->isChecked())
        value += 0x8000;

    writeSingleRegister(0xca, static_cast<unsigned short>(value));
}

void DlgModbusRtu::onRunTime()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    int value = ui->sbRunTime->value();
    QByteArray valueArray(4, 0x0);
    valueArray[0] = static_cast<char>((value >> 8) & 0xFF);
    valueArray[1] = static_cast<char>(value & 0xFF);
    valueArray[2] = static_cast<char>((value >> 24) & 0xFF);
    valueArray[3] = static_cast<char>((value >> 16) & 0xFF);
    writeMultiRegister(0xcc, 2, valueArray);
}

void DlgModbusRtu::onRunImpulse()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    int value = ui->sbRunImpulse->value();
    QByteArray valueArray(4, 0x0);
    valueArray[0] = static_cast<char>((value >> 8) & 0xFF);
    valueArray[1] = static_cast<char>(value & 0xFF);
    valueArray[2] = static_cast<char>((value >> 24) & 0xFF);
    valueArray[3] = static_cast<char>((value >> 16) & 0xFF);

    if (ui->rdoStopFirstImpulse->isChecked())
        writeMultiRegister(0xcc, 2, valueArray);
    if (ui->rdoImmediateImpulse->isChecked())
        writeMultiRegister(0xce, 2, valueArray);
}

void DlgModbusRtu::onRunAbsolutePosition()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    int value = ui->sbAbsolutePosition->value();
    QByteArray valueArray(4, 0x0);
    valueArray[0] = static_cast<char>((value >> 8) & 0xFF);
    valueArray[1] = static_cast<char>(value & 0xFF);
    valueArray[2] = static_cast<char>((value >> 24) & 0xFF);
    valueArray[3] = static_cast<char>((value >> 16) & 0xFF);

    if (ui->rdoStaticAbsolute->isChecked())
        writeMultiRegister(0xd0, 2, valueArray);
    if (ui->rdoImmediateAbsolute->isChecked())
        writeMultiRegister(0xe8, 2, valueArray);
}

void DlgModbusRtu::onSetAbsolutePosition()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    int value = ui->sbAbsolutePosition->value();
    QByteArray valueArray(4, 0x0);
    valueArray[0] = static_cast<char>((value >> 8) & 0xFF);
    valueArray[1] = static_cast<char>(value & 0xFF);
    valueArray[2] = static_cast<char>((value >> 24) & 0xFF);
    valueArray[3] = static_cast<char>((value >> 16) & 0xFF);
    writeMultiRegister(0xd2, 2, valueArray);
}

void DlgModbusRtu::onReadWarning()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    readSingleRegister(0xa3, 0x01);

    QTimer::singleShot(m_readWaitInterval, this, [=](){
        QByteArray recvBuffer = m_serialPort->recvBuffer();
        ui->leRecv->setText(recvBuffer.toHex(' '));

        if (recvBuffer.size() >= 7) {
            unsigned short value = recvBuffer.mid(3, 2).toUShort(nullptr, 16);
            ui->pteRslt->setPlainText(QStringLiteral("读取报警状态:%1").arg(value));
        }
    });
}

void DlgModbusRtu::onClearWarning()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    QMessageBox::StandardButton button = QMessageBox::question(this, QStringLiteral("RS485"), QStringLiteral("清除报警状态?"), QMessageBox::Yes | QMessageBox::No);
    if (button == QMessageBox::Yes) {
        writeSingleRegister(0xa4, 0x00);
    }
}

void DlgModbusRtu::onSend()
{
    if (!m_opened) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("串口未打开!"));
        return;
    }

    QString hex = ui->leSend->text().remove(QRegExp("\\s"));
    if (hex.isEmpty()) {
        QMessageBox::information(this, QStringLiteral("RS485"), QStringLiteral("无效的16进制字符!"));
        return;
    }

    QByteArray cmd = QByteArray::fromHex(hex.toLatin1());
    m_serialPort->clear();
    m_serialPort->write(cmd);

    QTimer::singleShot(m_readWaitInterval, this, [=](){ ui->leRecv->setText(m_serialPort->recvBuffer().toHex(' ')); });
}


